package cz.proks.easyhelpdesk.gae.api.impl.ws;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import cz.proks.easyhelpdesk.api.BaseApi;
import cz.proks.easyhelpdesk.api.exception.ApiException;
import cz.proks.easyhelpdesk.api.model.base.AnIdentifiableModel;
import cz.proks.easyhelpdesk.api.model.base.Id;

public abstract class BaseApiImpl<Entity extends AnIdentifiableModel>
		implements BaseApi<Entity> {
	private final Logger log = LoggerFactory.getLogger(getClass());
	
	protected abstract BaseApi<Entity> getCoreApi();
	
	@Override
	@RequestMapping(value = "/{id}", method = RequestMethod.GET)
	@ResponseBody	
	public Entity get(@PathVariable Long id) throws ApiException {
		log.debug("get():: Start with id '{}'", id);

		Entity entity = null;

		if (getCoreApi() == null)
			log.warn("get():: Service implementation not found!");
		else
			entity = getCoreApi().get(id);

		log.debug("get():: End with entity '{}'", entity);
		return entity;
	}

	

	@Override	
	public Long create(Entity entity) throws ApiException {
		return createImpl(entity).getId();
	}
	
	@RequestMapping(value = "/create", method = RequestMethod.PUT)
    @ResponseBody
	protected Id createImpl(@RequestBody Entity entity) throws ApiException {
        log.debug("create():: Start with entity '{}'", entity);

        Long id = null;

        if (getCoreApi() == null)
            log.warn("create():: Service implementation not found!");
        else
            id = getCoreApi().create(entity);

        log.debug("create():: End with id '{}'", id);
        return new Id(id);
	    
	}

	@Override
	@RequestMapping(value = "/update", method = RequestMethod.POST)
	@ResponseBody
	public void update(@RequestBody Entity entity) throws ApiException {
		log.debug("update():: Start with entity '{}'", entity);		

		if (getCoreApi() == null)
			log.warn("update():: Service implementation not found!");
		else
			getCoreApi().update(entity);

		log.debug("update():: End");		
	}
	
	@Override
	@RequestMapping(value = "/remove/{id}", method = RequestMethod.DELETE)
	@ResponseBody
	public void remove(@PathVariable Long id) throws ApiException {
		log.debug("delete():: Start with id '{}'", id);

		if (getCoreApi() == null)
			log.warn("delete():: Service implementation not found!");
		else {			
			getCoreApi().remove(id);
		}

		log.debug("delete():: End");		
	}

	/**
	 * Handling of client errors.
	 * 
	 * Returns HTTP status code 400 (bad request).
	 * 
	 * @param ex
	 *            The client error.
	 * @return The error message.
	 */
	// These exceptions denote client errors.
	@ExceptionHandler(IllegalArgumentException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ResponseBody
	public String handleClientErrors(Exception ex) {
		log.error("handleClientErrors():: Handled client error {}\n", ex.getMessage(), ex);

		return ex.getMessage();
	}

	/**
	 * Handling of server errors.
	 * 
	 * Returns HTTP status code 500 (internal server error).
	 * 
	 * @param ex
	 *            The server error.
	 * @return The error message.
	 */
	// All other exceptions are server errors.
	@ExceptionHandler(Exception.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	@ResponseBody
	public String handleServerErrors(Exception ex) {
		log.error("handleServerErrors():: Handled server error {}\n", ex.getMessage(), ex);

		return ex.getMessage();
	}

}
